package panda.client.listeners;

import panda.client.Cardpanda;
import panda.client.enumerations.CardScale;
import panda.client.ui.observable.ObservableLastMousedCard;
import panda.client.ui.widgets.BinExplorer;
import panda.client.ui.widgets.DraggableCard;
import panda.client.ui.widgets.NoteTip;
import panda.client.ui.widgets.ZoomManager;

import com.google.gwt.user.client.ui.KeyboardListener;
import com.google.gwt.user.client.ui.Widget;

/**
 * Central controller for key inputs in CardPanda. Make sure key inputs that fizzle (targets no initialized) fizzle
 * gracefully. Note that some updateServer calls are made directly here, while others are embedded in the methods in
 * ClientModel.java. This is a poor design choice that I have yet to fix =(
 * 
 * @author zane.tian@gmail.com
 */
public class PandaKeyboardListener implements KeyboardListener {
	public static boolean holdingShift = false;

	public void onKeyDown(Widget sender, char keyCode, int modifiers) {
		// NoteTip.get().logPersonalNote("keyDown: " + keyCode + " modifiers: " + modifiers);
		ObservableLastMousedCard lastMousedOver = Cardpanda.clientModel.getObsLastMousedCard();

		if(keyCode == KeyboardListener.KEY_SHIFT) {
			// NoteTip.get().log("Shift down");
			holdingShift = true;
		}

		if(Cardpanda.tokenMenu.isOpen()) {
			NoteTip.get().logPersonalNote("You need to close the token creator popup window to access CardPanda hotkeys.",
					true);

		} else {
			ZoomManager zoom = Cardpanda.zoomManager;

			/* testing */
			if(keyCode == '1') {
				NoteTip.get().logPersonalNote("ms since listener init: " + Cardpanda.getElapsedMsSinceStart(), true);
			}

			/* zoom */
			if(keyCode == 'Z') {
				if(!zoom.isZooming() && lastMousedOver.hasCard()) {
					if(lastMousedOver.getCard().equals(lastMousedOver.getCard())) {
						zoom.show(lastMousedOver.getCard());
					}
				}
			}

			/* Tap the last moused over draggable card if lastmousedovercard isn't null and if the card is in play */
			if(keyCode == 'T' && lastMousedOver.hasCard() && Cardpanda.clientModel.inPlay(lastMousedOver.getCard())) {
				System.out.println("lastmousedover's card: " + lastMousedOver.getCard().getName());

				DraggableCard tapTarget = lastMousedOver.getCard();
				Cardpanda.clientModel.tapToggle(tapTarget);

				updateServer();
			}

			BinExplorer selectedBinEx = Cardpanda.clientModel.getSelectedBinEx();
			
			/**
			 * when the listbox refreshes it sets the selectedIndex to -1 very temporarily. this causes exceptions, hence
			 * the following code
			 */
			if(keyCode == 'R' && selectedBinEx.getListBoxSelectedIndex() != -1) {
				if(selectedBinEx != null) {
					if(selectedBinEx.isEmpty()) {
						// TODO need bin owner + name
						NoteTip.get().logPersonalNote(
								"You can't play or reveal a card from your " + selectedBinEx.getName()
										+ " because it is empty.", true);
					} else {
						DraggableCard removed = selectedBinEx.removeSelectedCard();
						assert !removed.isTapped() : "This card, " + removed.getName()
								+ ", should not be tapped inside a bin";
						Cardpanda.clientModel.addCardInPlay(removed, 40, Cardpanda.canvasHeight / 2
								- CardScale.QUARTER.getHeight() / 2);

						String name = Cardpanda.clientModel.getSessionID().getName();
						String logForMe = "You reveal " + removed.getName() + " from your " + selectedBinEx.getName() + ".";
						String logForOthers = name + " reveals " + removed.getName() + " from " + name + "'s "
								+ selectedBinEx.getName();
						NoteTip.get().log(logForMe, logForOthers);
					}

					updateServer();
				}
			}

			/* Shuffle cards in hand into library and draw 7 cards: a convenience function for testing. */
			if(keyCode == 'M') {
				// Panda.clientModel.drawSevenCards();
				// updateServer();
				NoteTip.get().logPersonalNote("The M key no longer works :P", true);
			}

			/* shuffle */
			if(keyCode == 'S') {
				Cardpanda.clientModel.shuffleLibrary();
				updateServer();
			}
			
			/* reveal a card at raNdom from your hand */
			if(keyCode == 'N') {
				Cardpanda.clientModel.revealRandomCardInHand(true);
			}

			/* reveal a card from the top of your library */
			if(keyCode == 'Q') {
				Cardpanda.clientModel.revealTopCardOfLibrary(true);
			}

			/* put a card at the bottom of your library */
			if(keyCode == 'B') {
				Cardpanda.clientModel.putCardAtLibraryBottom(true);
			}

			/* draw a card */
			if(keyCode == 'A') {
				Cardpanda.clientModel.drawCardFromLibrary(true);
			}

			/* Set z-index TODO: shouldn't trigger when the main canvas doesn't have focus. */
			if(keyCode == KeyboardListener.KEY_UP) {
				if(lastMousedOver.hasCard()) {
					DraggableCard card = lastMousedOver.getCard();
					card.setZIndex(card.getZIndex() + 1);

					String logForMe = "You set " + card.getName() + "'s z-index to " + card.getZIndex();
					String logForOthers = Cardpanda.clientModel.getSessionID().getName() + " sets " + card.getName()
							+ "'s z-index to " + card.getZIndex();
					NoteTip.get().log(logForMe, logForOthers);
					updateServer();
				}
			}

			if(keyCode == KeyboardListener.KEY_DOWN) {
				if(lastMousedOver.hasCard()) {
					DraggableCard card = lastMousedOver.getCard();
					card.setZIndex(card.getZIndex() - 1);
					String logForMe = "You set " + card.getName() + "'s z-index to " + card.getZIndex();
					String logForOthers = Cardpanda.clientModel.getSessionID().getName() + " sets " + card.getName()
							+ "'s z-index to " + card.getZIndex();
					NoteTip.get().log(logForMe, logForOthers);
					updateServer();
				}
			}

			/* Bin Explorer Visibility Toggles TODO: add opponent visibility stuff here with h = hand vis */
			if(keyCode == 'L') {
				Cardpanda.clientModel.toggleLibraryVisibility();
			}

			if(keyCode == 'G') {
				Cardpanda.clientModel.toggleGraveyardVisibility();
			}
		}
	}

	private void updateServer() {
		Cardpanda.sendModelUpdateToServer(Cardpanda.clientModel.getSessionID());
	}

	public void onKeyPress(Widget sender, char keyCode, int modifiers) {
	// if(keyCode == KEY_ESCAPE) {
	// CanvasLog.get().clearLog();
	// }
	}

	public void onKeyUp(Widget sender, char keyCode, int modifiers) {
		// CanvasLog.get().log("keyUp: " + keyCode + " modifiers: " + modifiers);

		if(keyCode == KeyboardListener.KEY_SHIFT) {
			// NoteTip.get().log("Shift up");
			holdingShift = false;
		}

		ZoomManager zoom = Cardpanda.zoomManager;
		if(keyCode == 'Z') {
			zoom.hide();
		}
	}
}